package com.czk.bigdata;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.ParameterizedType;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * easyexcel大批量导出数据----分批次，导出
 *
 * @author chenzhangkun
 * @ClassName EasyExcelExport
 * @description: TODO
 * @date 2024年05月06日
 */
@Slf4j
public abstract class EasyExcelExport<T, S> {


	public void easyExcelBatchExport(String fileName, String sheetName, HttpServletResponse response) {
		this.easyExcelBatchExport(fileName, sheetName, 100000, response);
	}

	public void easyExcelBatchExport(String fileName, String sheetName, Integer sheetSize, HttpServletResponse response) {
		fileName = fileName + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xlsx";
		// 当前处于第几个sheet
		int currentSheet = 1;
		// 总共写入的条数
		int totalLine = 0;
		// 当前写入excel的批次(第几页)
		int currentBatch = 1;
		// 行号,当前写入的是第几条数据
		int lineNum = 1;

		long startTime = System.currentTimeMillis();
		try {
			response.setCharacterEncoding("utf-8");
			// 告诉浏览器用什么软件可以打开此文件
			response.setHeader("content-Type", "application/vnd.ms-excel");
			// 下载文件的默认名称
			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));

			ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]).build();
			WriteSheet sheet = EasyExcel.writerSheet(sheetName).build();

			while (true) {
				// 获取数据，然后currentBatch+1,下次调用就会获取新的数据
				List<S> sourceDataList = getData(currentBatch);
				currentBatch++;

				List<T> exportEntityList = new ArrayList<>();
				if (CollUtil.isNotEmpty(sourceDataList)) {
					totalLine += sourceDataList.size();
					log.info("EasyExcel开始写入第{}批数据,当前批次数据大小为{}", currentBatch - 1, sourceDataList.size());
					for (S sourceData : sourceDataList) {
						exportEntityList.add(convertSourceData2ExportEntity(sourceData, lineNum));
						lineNum++;

						// 当前sheet数据已经到达最大值，将当前数据全写入当前sheet，下一条数据就会写入新sheet
						if (lineNum > sheetSize) {
							excelWriter.write(exportEntityList, sheet);
							exportEntityList.clear();
							lineNum = 1;
							currentSheet++;
							sheet = EasyExcel.writerSheet(sheetName + currentSheet).build();
						}
					}

					// 写入excel
					excelWriter.write(exportEntityList, sheet);
				} else {
					// 未获取到数据,结束
					break;
				}
			}
			excelWriter.finish();
		} catch (Exception e) {
			log.error("EasyExcel导出异常", e);
		}

		log.info("EasyExcel导出数据结束,总数据量为{},耗时{}ms", totalLine, (System.currentTimeMillis() - startTime));

	}

	/**
	 * 将原数据对象转换为需要导出的目标对象
	 *
	 * @param sourceData 原对象
	 * @param lineNum    行号
	 */
	public abstract T convertSourceData2ExportEntity(S sourceData, Integer lineNum);

	/**
	 * 获取原始数据,通过currentBatch参数分页获取数据。
	 *
	 * @param currentBatch 获取第几批(页)数据,通过该参数分页查询,每次调用自动递增。不分批次导出时可以忽略该参数
	 */
	public abstract List<S> getData(int currentBatch);
}
